#include "L610.h"
#include "globalDef.h"
#include "string.h"
#include "algorithm.h"
#include "uart_hw.h"
#include "L610_hw.h"
#include "CarMonitor.h"
#include "OneSecProcess.h"
#include "paraTable.h"
#include "SPI_Flash.h"
#include "IAP.h"
#include "storeCarInf.h"
#include "tim_hw.h"
#include "sleep.h"
#include "debug_prt.h"
#include "CANProcess.h"
#include "Flash_user.h"
#include "stdlib.h"
#include "peripheral.h"
#include "fmc_flash.h"
#include "IO_Ctrl_hw.h"

#if def_EngineStart
#include "EngineStart.h"
#endif
extern void setSelfCheckResult(uint8_t bitX);
extern void InitCANConfig(void);
extern void turnOffCANs(void);
extern Control_Vehicle tagCarC;
extern printinfo_t prt_inf;
L610_typedef	tagL610;
extern GLBUS_bmsg GLBUS_bmsg_date;
etc_recv_msg_t  etc_recv_msg;
veh_seed_key_msg_t veh_seed_msg, veh_key_msg;
//启动从L610的要包
//返回0成功，1失败
uint8_t startUpFromL610(uint32_t fileSize)
{
	uint8_t reDa = 0;
	
	//目前最大84k用于存储程序
	if (fileSize > (FMC_APP_END_ADR - FMC_APP_START_ADR))
	{
		return 1;
	}
	
	//写入标记
	reDa = writeGD_fmc_UpFlag(fileSize);
	
	//如果写入标记失败，再写1次
	if (reDa == 0x01)
	{
		reDa = writeGD_fmc_UpFlag(fileSize);
	}
	
	if (reDa != 0x00)
	{
		//擦除标记
		eraseGD_fmc_UpFlag();
	}

	return reDa;
}


//初始化L610模块变量
void initL610Var(void)
{
	memset(&tagL610, 0, sizeof(L610_typedef));
	tagL610.heatBeatDlySec = 0xFFF0;	//保证刚开机发一条心跳
	
	//默认L610每过24小时自动重启1次
	tagL610.RebootL610Cnt = 2 * 3600 + getRandom_u32()%3600;

	/*初始化ETC数据信息*/
	memset((uint8_t *)&etc_recv_msg, 0x00, sizeof( etc_recv_msg_t ) );
	/*初始化车身种子和密钥数据结构体*/
	memset( (uint8_t *)&veh_seed_msg, 0x00, sizeof( veh_seed_key_msg_t));
	memset( (uint8_t *)&veh_key_msg, 0x00, sizeof( veh_seed_key_msg_t));
}

//解析具体命令
uint32_t parse_L610_uart_data(uint8_t* pdata, uint32_t len)
{
	uint8_t msg_id[2];
	uint8_t msg_prop[2];
	uint32_t imsg_id;
	uint32_t msg_len;
	uint8_t car_id[6];
	uint8_t msg_serial[2];
	uint32_t imsg_serial;
	uint8_t plus_pac_sta;	//分包
	uint8_t * rdata = pdata;	
	uint8_t * bdata;	//消息体起始位置指针body data
	uint32_t idx;
	uint32_t reDa;
	__IO uint16_t curPac, allPac;
	printinfo_t prt_msg = {0};
	
	//通用应答相关变量
	__IO uint16_t answerSerial;
	__IO uint16_t answerID;
	__IO uint8_t answerResult;
	
	//	//串口读写Flash相关
	//	uint32_t FlashAdr;
	//	uint32_t FlashLen;
	
	#if EnableDMA_Test_Def
	static u32 cntH = 0;
	static u32 cntL = 0;
	#endif
	
	//清重启L610计时
	clearRebootL610Sec();
	
	//消息ID
	memcpy(msg_id, rdata, 2);
	imsg_id = msg_id[0] * 0x100 + msg_id[1];

	//消息体属性
	memcpy(msg_prop, &rdata[2], 2);
	msg_len = (msg_prop[0] & 0x03) * 0x100 + msg_prop[1];
	msg_len &= 0x03FF;
	if ((msg_prop[0] & 0x80) == 0x80)
	{
		msg_len += 1024;
	}
	
	plus_pac_sta = (msg_prop[0] >> 5) & 0x01;

	//车辆管理id
	memcpy(car_id, &rdata[4], 6);

	//流水号
	memcpy(msg_serial, &rdata[10], 2);
	imsg_serial = msg_serial[0] * 0x100 + msg_serial[1];

	//封装项
	if (plus_pac_sta == 1)
	{
		allPac = rdata[12] * 0x100 + rdata[13];
		curPac = rdata[14] * 0x100 + rdata[15];
		idx = 16;
	}
	else
	{
		allPac = 0;
		curPac = 0;
		idx = 12;
	}
	
	//有可能收到的数据msg_len是错误的，其它部分正确，这也需要丢弃
	if ( (msg_len + idx + 1) != len )
	{
		#if _EN_L610Debug_def
		printf("pack len err\r\n");
		#endif
		return 2;
	}
	
	//消息体起始字节
	//	memcpy(msg_info, &rdata[idx], msg_len);
	bdata = &rdata[idx];
	
	#if _EN_L610Debug_def
	printf("imsg_id = %02x\r\n", imsg_id);
	#endif
	
	tagL610.OnlyL610GeneralAnswer = 0;	//需要主循环处理的=0；不需要主循环处理的=1
	
	switch (imsg_id)
	{
	case 0x1050:	//L610通知IAP升级主程序
		saveCarInf();//升级时保存一遍
		if (bdata[0] == 0x01)
		{
			reDa = startUpFromL610( (bdata[1]<<24) | (bdata[2]<<16) | (bdata[3]<<8) | bdata[4]);
		}
		else
		{
			reDa = 2;
		}
		send_general_answer_to_L610(imsg_id, imsg_serial, (uint8_t)reDa);
		
		if (reDa == 0x00)
		{
			reBootMe();
		}
		
		break;	
	case 0x1039:	//L610下发时间
			setRebootL610Time(bdata);
			break;
		
	//	case 0x1035:	//写CA证书
			
	//		reDa = uartWriteFlash_CA(msg_len, bdata);
	//		send_general_answer_to_L610(imsg_id, imsg_serial, reDa);
	//		break;
	//	case 0x1036:	//读CA证书
	//		uartReadFlash_CA();
	//		break;
		

	case 0x1033:
		reDa = 0;
		if (bdata[0] == 0x01)		//关闭CAN
		{
			turnOffCANs();
		}
		else if (bdata[0] == 0x02)	//开启CAN
		{
			InitCANConfig();
		}
		else if (bdata[0] == 0x03)	//重启CAN
		{
			tagL610.restartCANHardware = 1;
		}
		else
		{
			reDa = 2;
		}
		send_general_answer_to_L610(imsg_id, imsg_serial, reDa);
		break;			

	case 0x1030:	//寻车
		send_general_answer_to_L610(imsg_id, imsg_serial, 0);
		if(tagCarC.Light_Ctrl == 0)
		{
			#if USER_HXCX_ARCFOX
			if((bdata[0] == 0x02)||(bdata[0] == 0x03))//
			{
				if(bdata[0] == 0x03)
				{
					tagCarC.Light_Ctrl = 0x83;
				}
				else
				{
					tagCarC.Light_Ctrl = 0x81;	
				}
			}
			#else
			if((bdata[0] == 0x02)||(bdata[0] == 0x03))//
			{
				tagCarC.Light_Ctrl = 0x81;
			}
			#endif
		}
		if(tagCarC.Whistle_Ctrl == 0)
		{
			#if USER_HXCX_ARCFOX
			if(bdata[0] == 0x01)//
			{
				tagCarC.Whistle_Ctrl = 0x81;
			}
			#else
			if((bdata[0] == 0x01)||(bdata[0] == 0x03))//
			{
				tagCarC.Whistle_Ctrl = 0x81;
			}		
			#endif
		}
		break;

	case 0x1031:	//车锁
		reDa = 1;
		if(tagCarC.Lock_Ctrl == 0)
		{
			if ((bdata[0] == 0x01)||(bdata[0] == 0x07))	//
			{
				tagCarC.Lock_Ctrl = 0x81;
			}
			else if((bdata[0] == 0x02)||(bdata[0] == 0x08))
			{
				tagCarC.Lock_Ctrl = 0x80;
			}
			reDa = 0;
		}
		
		send_general_answer_to_L610(imsg_id, imsg_serial, reDa);
		break;
		
	case 0x10A5:	//控制开关天窗、升降玻璃
		reDa = 0;
		
		if (((bdata[0] == 0x02) || (bdata[0] == 0x22)) &&
			(tagCarC.Window_Ctrl == 0x00))
		{
			if(bdata[0] == 0x22)
			{
				tagCarC.Window_Ctrl = 0x83;
			}
			else
			{
				tagCarC.Window_Ctrl = 0x81;
			}
		}
		if (((bdata[0] == 0x01) || (bdata[0] == 0x21)) &&
			(tagCarC.Window_Ctrl == 0x00))
		{
			if(bdata[0] == 0x21)
			{
				tagCarC.Window_Ctrl = 0x82;
			}
			else
			{
				tagCarC.Window_Ctrl = 0x80;
			}
			
		}
		if (((bdata[0] == 0x11)) &&
			(tagCarC.Skylight_Ctrl == 0x00))
		{
			tagCarC.Skylight_Ctrl = 0x81;
		}
		if (((bdata[0] == 0x12)) &&
			(tagCarC.Skylight_Ctrl == 0x00))
		{
			tagCarC.Skylight_Ctrl = 0x80;
		}
		
		if((bdata[0] == 0x01) || (bdata[0] == 0x02) ||
			(bdata[0] == 0x11) || (bdata[0] == 0x12) ||
			(bdata[0] == 0x21) || (bdata[0] == 0x22))
		{
			
		}
		else
		{
			reDa = 1;
		}
		send_general_answer_to_L610(imsg_id, imsg_serial, reDa);
		break;
	
	case 0x1032:	//继电器供电断电
		if ( (bdata[0] == 0x01) || (bdata[0] == 0x02) )
		{
			reDa = saveRelay2Flash(bdata[0]);
			tagL610.relayPowerCtrl = bdata[0];
			#if USER_HXCX_ARCFOX
			if(tagL610.relayPowerCtrl == 0x02)
			{
				if(tagCarC.Window_Ctrl == 0x00)
				{
					tagCarC.Window_Ctrl = 0x83;  //升窗（车窗+天窗）
				}
			}
			#endif
		}
		else
		{
			reDa = 2;
		}
		send_general_answer_to_L610(imsg_id, imsg_serial, reDa);
		break;

	
	case 0x1005:	//心跳
		send_general_answer_to_L610(imsg_id, imsg_serial, 0);
		tagL610.OnlyL610GeneralAnswer = 1;	//不需要主循环处理的=1
		break;
	
	case 0x1011:	//采集IO状态
		parseCarIO(bdata, msg_len);
		
		break;
	
	case 0x1012:	//L610要求重启自己
	case 0x107A:
		if ( bdata[0] == 0x05 )
		{			
			rebootL610();			//重启L610
			send_general_answer_to_L610(imsg_id, imsg_serial, 0);
		}
	#if ( OBU_POWER_CONTRL_DEF == 1 )
		else if( bdata[0] == 0x06 )
		{
			OBUPowerOff();
		}
		else if( bdata[0] == 0x07 )
		{
			OBUPowerOn();
		}
	#endif
		break;
		
	case 0x1013:	//查询版本号
		sendGDVersion2L610();
		tagL610.OnlyL610GeneralAnswer = 1;	//不需要主循环处理的=1
		break;
	
	case 0x1017:	//查询车辆状态
		tagL610.activePushMsgSta = 1;
		askCarInf(bdata, msg_len);
		tagL610.OnlyL610GeneralAnswer = 1;	//不需要主循环处理的=1
		break;
	
	case 0x1018:	//写UTC
		writeUTC(hex4CombineOne(bdata));
		send_general_answer_to_L610(imsg_id, imsg_serial, 0);
		tagL610.OnlyL610GeneralAnswer = 1;	//不需要主循环处理的=1
		break;
	
	case 0x1019:	//读UTC
		send_utc_to_L610();
		tagL610.OnlyL610GeneralAnswer = 1;	//不需要主循环处理的=1
		break;
	
//	case 0x101A:	//写参数表
//		reDa = L610WriteParaTable(bdata, msg_len);
//		send_general_answer_to_L610(imsg_id, imsg_serial, (uint8_t)reDa);
//		tagL610.OnlyL610GeneralAnswer = 1;	//不需要主循环处理的=1
//		break;
	
//	case 0x101B:	//读参数表
//		reDa = L610ReadParaTable();
//		if (reDa != 0)
//		{
//			send_general_answer_to_L610(imsg_id, imsg_serial, (uint8_t)reDa);
//		}
//		tagL610.OnlyL610GeneralAnswer = 1;	//不需要主循环处理的=1
//		break;
	
//		case 0x3010:	//PC写参数表
//		reDa = L610WriteParaTable(bdata, msg_len);
//		send_general_answer_to_PC(imsg_id, imsg_serial, (uint8_t)reDa);
//		tagL610.OnlyL610GeneralAnswer = 1;	//不需要主循环处理的=1
//		break;
	
//	case 0x3011:	//PC读参数表
//		reDa = PCReadParaTable();
//		if (reDa != 0)
//		{
//			send_general_answer_to_PC(imsg_id, imsg_serial, (uint8_t)reDa);
//		}
//		tagL610.OnlyL610GeneralAnswer = 1;	//不需要主循环处理的=1
//		break;


//	//写Flash存储器
//	case 0x101C:
//		FlashAdr = hex4CombineOne(bdata);
//		FlashLen = hex4CombineOne(bdata+4);
//		if (FlashLen < MAX_RECV_L610_LEN)
//		{
//			reDa = uartWriteFlash(FlashAdr, FlashLen, &bdata[8]);
//		}
//		else
//		{
//			reDa = 3;
//		}
//		send_general_answer_to_L610(imsg_id, imsg_serial, reDa);
//		tagL610.OnlyL610GeneralAnswer = 1;	//不需要主循环处理的=1
//		break;
//	
//	//读Flash存储器
//	case 0x101D:
//		FlashAdr = hex4CombineOne(bdata);
//		FlashLen = hex4CombineOne(bdata+4);
//		if (FlashLen < MAX_RECV_L610_LEN)
//		{
//			reDa = uartReadFlash(FlashAdr, FlashLen);
//		}
//		else
//		{
//			reDa = 3;
//		}
//		send_general_answer_to_L610(imsg_id, imsg_serial, reDa);
//		tagL610.OnlyL610GeneralAnswer = 1;	//不需要主循环处理的=1
//		break;
//	
//	//擦除Flash存储器块
//	case 0x101E:
//		FlashAdr = hex4CombineOne(bdata);
//		FlashLen = hex4CombineOne(bdata+4);
//		if (FlashLen < 1024)
//		{
//			reDa = uartEraseFlash(FlashAdr, FlashLen);
//		}
//		else
//		{
//			reDa = 3;
//		}
//		send_general_answer_to_L610(imsg_id, imsg_serial, reDa);
//		tagL610.OnlyL610GeneralAnswer = 1;	//不需要主循环处理的=1
//		break;
//	//初始化总线
//	case 0x101F:
//		reDa = Flash_Init();
//		send_general_answer_to_L610(imsg_id, imsg_serial, reDa);
//		tagL610.OnlyL610GeneralAnswer = 1;	//不需要主循环处理的=1
//		break;		
		//PC透传给L610
	case 0x3001:
		if(bdata[0] != 0x13)
		{
			send_general_package_to_uart(0x3001, bdata, msg_len, imsg_serial,1, 1);
		}
		else
		{
			if((strlen((char *)prt_inf.dev_id) == 0) &&
			 (strlen((char *)prt_inf.ble_mac) == 0) &&
			 (strlen((char *)prt_inf.ccid_in) == 0))
			 {
				 send_general_package_to_uart(0x3001, bdata, msg_len, imsg_serial,1, 1);
			 }
			 else
			 {
				 uint8_t sd_msg[100]={0};
				 sd_msg[0] = 0x14;
				 memcpy(&sd_msg[1],prt_inf.dev_id,4);
				 memcpy(&sd_msg[5],prt_inf.car_id,6);
				 memcpy(&sd_msg[11],prt_inf.ble_mac,6);
				 memcpy(&sd_msg[17],prt_inf.ccid_in,20);
				 memcpy(&sd_msg[37],prt_inf.ccid_out,20);
				 send_general_package_to_uart(0x2020, sd_msg, 57, imsg_serial,1, 0);
			 }
		}
		tagL610.OnlyL610GeneralAnswer = 1;	//不需要主循环处理的=1
		break;
	
	//L610透传给PC
	case 0x2020:
		send_general_package_to_uart(0x2020, bdata, msg_len, imsg_serial,1, 0);
		tagL610.OnlyL610GeneralAnswer = 1;	//不需要主循环处理的=1
		break;
	
	case 0x1020:	//要求重启GD32
		send_general_answer_to_L610(imsg_id, imsg_serial, 0);
		reBootMe();
		break;

//	case 0x1015:	//远程升级
//		reDa = IapStoreData(allPac, curPac, bdata, msg_len);
//		send_general_answer_to_L610(imsg_id, imsg_serial, reDa);
//		break;

	case 0x1021:	//清车身历史数据
		clearCarInf();
		send_general_answer_to_L610(imsg_id, imsg_serial, 0);
		tagL610.OnlyL610GeneralAnswer = 1;	//不需要主循环处理的=1
		break;
	
	case 0x1000:  //通用应答
		{	
			tagL610.OnlyL610GeneralAnswer = 1;	//不需要主循环处理的=1
			//流水号
			answerSerial = bdata[0]*0x100 + bdata[1];
			//消息ID
			answerID = bdata[2]*0x100 + bdata[3];
			//结果
			answerResult = bdata[4];
			switch (answerID)
			{
				case 0x1000:	
					//收到心跳应答
					break;
			}
		}
		break;
		case 0x1061:
		{
			if(gpio_output_bit_get(GPIOB,GPIO_PIN_15) == RESET)
			{
				#if (CONFIG_USER_SIM == 0)
				gpio_bit_set(GPIOB,GPIO_PIN_15);
				#elif (CONFIG_USER_SIM == 1)
				//High-esim
				gpio_bit_set(GPIOB,GPIO_PIN_15);
				#else
				gpio_bit_reset(GPIOB,GPIO_PIN_15);
				#endif
				saveSwSIMtoFlash(2);
			}
			else
			{
				#if (CONFIG_USER_SIM == 0)
				gpio_bit_reset(GPIOB,GPIO_PIN_15);
				#elif (CONFIG_USER_SIM == 1)
				//High-esim
				gpio_bit_set(GPIOB,GPIO_PIN_15);
				#else
				gpio_bit_reset(GPIOB,GPIO_PIN_15);
				#endif
				
				saveSwSIMtoFlash(1);
			}
			send_general_answer_to_L610(imsg_id, imsg_serial, 0);
		}	
		break;
		case 0x10A6:
		{
			#if def_EngineStart
			//流水号
			tagEngS.startp_sn = bdata[0]*0x100 + bdata[1];
			//消息ID
			tagEngS.startp_cmd = bdata[2]*0x100 + bdata[3];
			//控制命令
			tagEngS.startp_ctl = bdata[4];
			#endif
		}	
		break;
		case 0x10A7:
		{
			if((strlen((char *)bdata) != 0))	
			{
				memcpy(&prt_msg,&prt_inf,sizeof(printinfo_t));
				memcpy(prt_msg.car_id,bdata,6);
				if(memcmp(prt_inf.ccid_in,&bdata[6],20) != 0)
				{
					memcpy(prt_msg.ccid_out,&bdata[6],20);
				}
				if(0 == saveprintinfo_t(&prt_msg))
				{
					getprintinfo_t(&prt_inf);
				}
			}
			send_general_answer_to_L610(imsg_id, imsg_serial, 0);
		}
		break;
		case 0x1081:	/*查询 清除车辆故障码*/
		{
			if( bdata[0] == 0x01 )		/*清除车辆故障码*/
			{
				tagCarC.DTC_Ctrl = 0x81;
				tagL610.dtc_state = 0x01;
			}
			else if( bdata[0] == 0x02 )	/*查询车辆故障码*/
			{
				tagCarC.DTC_Ctrl = 0x82;
				tagL610.dtc_state = 0x02;
			}
			send_general_answer_to_L610(imsg_id, imsg_serial, 0);
		}
		break;
		case 0x1082:	/*向OBU发送数据*/
		{
			send_etc_msg_handle( bdata, msg_len );
		}
		break;
		case 0x1083://新增保养信息存储2023/04/12
		{
			if(1 == set_car_Health( bdata,msg_len ))
			{
				send_general_answer_to_L610(imsg_id, imsg_serial, 0);
			}
		}
		break;
		case 0x1084:	/*L610向GD发送安全KEY*/
		{
			if( vehicle_key_save_to_flash( bdata, msg_len ) == 1 )
			{
				/*数据存储成功*/
			}
		}	
		break;
		case 0x1085:	/*L610 向GD 断电指令-房车项目*/
		{	
			if( bdata[0] == 0x01 )				/*启动*/
			{
				tagCarC.RV_Power_Ctrl = 0x01;
			}
			else if( bdata[0] == 0x02 )			/*关闭*/
			{
				tagCarC.RV_Power_Ctrl = 0x02;
			}
			else if( bdata[0] == 0x03 )	
			{
				tagCarC.RV_Power_Ctrl = 0x03; 	/*ADAS激活*/
			}
			send_general_answer_to_L610(imsg_id, imsg_serial, 0);
		}
		break;
	#if( ADAS_COM_FUNCTION_DEF ==1 )
		case 0x1100:	/*ADAS查询信息 ADAS->TBOX*/
		{
			uint8_t adas_msg[32] = { 0 },adas_len = 0;
			adas_len = adas_search_info_function( adas_msg,bdata[0]);
			if( adas_len != 0 )
			{
				send_general_package_to_uart(0x2100, adas_msg, adas_len, imsg_serial,1, 2);
			}
		}
		break;
	#endif
	}
	return 0;
}

//获取车辆故障码信息
//返回 1 - 成功，0 - 失败
uint8_t vehicle_fault_code_infor_get( void )
{
	uint8_t ret = 0;

	if( tagL610.dtc_state == 0x01 )
	{
		if( tagCarC.DTC_Ctrl == 0x00 )	/*清除故障码时不要进行数据应答*/
		{
			tagL610.dtc_state = 0x00;
		}
	}
	if( tagL610.dtc_state == 0x02 )
	{
		if( tagCarC.DTC_Ctrl == 0x00 )	/*当状态变为0x00 时表示数据已经完成*/
		{
			tagL610.dtc_state = 0x00;
			ret = 1;
		}
	}
	
	return ret;
}

//发送ETC 信息
void send_etc_msg_handle( uint8_t* pdata, uint32_t len )
{
	if(( pdata != NULL ) && ( len > 0 ))
	{
		uart_send_to_PC( pdata, len );
	}
}

//故障码状态读取
uint8_t vehicle_fault_code_state_read( void )
{
	if(( tagCarC.DTC_Read & 0x01 ) == 0x01 )
	{
		tagCarC.DTC_Read &= 0xFE;
		return 1;
	}
	
	return 0;
}
//保养信息状态读取
uint8_t vehicle_main_infor_state_read( void )
{
	if(( tagCarC.DTC_Read & 0x02 ) == 0x02 )
	{
		tagCarC.DTC_Read &= 0xFD;
		return 1;
	}
	
	return 0;
}

//保存L610下发的密钥KEY
uint8_t vehicle_key_save_to_flash( uint8_t *data, uint8_t len )
{
	if(( data != NULL ) && ( len != 0 ))
	{
		if( data[0] == 0 )
		{
			memset( (uint8_t *)&veh_key_msg, 0x00, sizeof( veh_seed_key_msg_t ));
		#if 0
			if( savePara1024WithAdr( FMC_KEY_INFO_ADR, ( uint8_t *)&veh_key_msg, sizeof( veh_seed_key_msg_t ) ) == 0 )	/*保存成功*/
			{
				return 1;
			}
		#else
			return 1;
		#endif
		}
		else
		{
			veh_key_msg.len = data[0];
			if( veh_key_msg.len < VEH_SEED_KEY_LEN )
			{
				memcpy( (uint8_t *)veh_key_msg.data,(uint8_t *)&data[1], veh_key_msg.len );
			#if 0
				if( savePara1024WithAdr( FMC_KEY_INFO_ADR, ( uint8_t *)&veh_key_msg, sizeof( veh_seed_key_msg_t ) ) == 0 )	/*保存成功*/
				{
					return 1;
				}
			#else
				return 1;
			#endif
			}
		}
	}
	return 0;
}

#if 0
//从FLASH中读取KEY数据
void vehicle_key_read_form_flash( void )
{
	memset( (uint8_t *)&veh_key_msg, 0x00, sizeof( veh_seed_key_msg_t ));
	savePara1024WithAdr( FMC_KEY_INFO_ADR, ( uint8_t *)&veh_key_msg, sizeof( veh_seed_key_msg_t ));
	if( readPara1024WithAdr( FMC_KEY_INFO_ADR, ( uint8_t *)&veh_key_msg, sizeof( veh_seed_key_msg_t ) ) != 0 )	/*数据读取失败*/
	{
		memset( (uint8_t *)&veh_key_msg, 0x00, sizeof( veh_seed_key_msg_t ));
	}
}
#endif

//读取车辆密钥KEY信息
uint8_t vehicle_key_read_infor( uint8_t *infor )
{
	if(( veh_key_msg.len != 0 ) && ( infor != NULL ))
	{
		memcpy( ( uint8_t *)infor, ( uint8_t *)veh_key_msg.data, veh_key_msg.len );
	}
	
	return veh_key_msg.len;
}

//设置SEED数据
void vehicle_seed_infor_set( uint8_t *infor, uint8_t len )
{
	if( len < VEH_SEED_KEY_LEN )
	{
		veh_seed_msg.len = len;
		memcpy( (uint8_t *)veh_seed_msg.data, (uint8_t *)infor, veh_seed_msg.len );
	}
}

/*获取SEED数据*/
uint8_t vehicle_seed_infor_send( void )
{
	uint8_t len = 0;
	
	if(( veh_seed_msg.len != 0 ) && ( veh_key_msg.len == 0 ))
	{
		vehicle_safety_seed_report( (uint8_t *)&veh_seed_msg );
		memset( (uint8_t *)&veh_seed_msg, 0x00, sizeof( veh_seed_key_msg_t ));
	}
	
	return len;
}
 
/*车身数据处理功能函数*/
void vehicle_data_handle_function( void )
{	
	/*查询车辆故障码状态，成功后发送到L610*/
	if( vehicle_fault_code_infor_get() == 0x01 )
	{
		answer_fault_code_information_send( 0xAF );
	}
	/*车辆保养信息、故障码上报，上报机制：车辆启动时读取故障码信息*/
	if( vehicle_fault_code_state_read() == 0x01 )
	{
		answer_fault_code_information_send( 0xAF ); /*上报故障码信息*/
	}
	if( vehicle_main_infor_state_read() == 0x01 )
	{
		reported_car_Health();	/*上报保养信息*/
	}
	/*发送车身安全SEED*/
	vehicle_seed_infor_send();
#if 0
	//桂林公交bms管理任务
	if (GLBUS_bmsg_date.newdatast == 1)
	{
		reported_car_bms();
	}
#endif
	snwrv_data_msg_send();		/*塞纳房车数据发送*/
#if( ADAS_COM_FUNCTION_DEF ==1 )
	adas_send_info_function();
#endif
#if( MCU_SAVE_DATA_ENABLE == 0 )
	mcu_form_cpu_data_request();
#endif
}

u8 rxL610Buf[MAX_RECV_L610_IRT_LEN]={0};
u32 rxL610RdIdx = MAX_RECV_L610_IRT_LEN;	//标识已经处理的数据
u32 rxL610RcvIdx = MAX_RECV_L610_IRT_LEN;	//标识已经接收到的原始数据
u32 Rx2BufIdx = 0;	//收到的数据从采用从0增加的下标

u8 rxPCBuf[MAX_RECV_L610_IRT_LEN];
u32 rxPCRdIdx = MAX_RECV_L610_IRT_LEN;	//标识已经处理的数据
u32 rxPCRcvIdx = MAX_RECV_L610_IRT_LEN;	//标识已经接收到的原始数据
u32 RxPCBufIdx = 0;	//收到的数据从采用从0增加的下标


//L610主处理进程
void L610Process(void)
{
	uint8_t da;
	uint8_t reDa = 0;
	static uint16_t MsOld;
	uint16_t MsNew;
	//预防措施
	{
		clear_dma0_ch5_err();
	}
	//这样写，防止丢失数据
	if (rxL610RcvIdx == rxL610RdIdx)
	{
		//取出DMA剩余字节数
		rxL610RcvIdx = dma_transfer_number_get(DMA0, DMA_CH5);
	#if debugDMADef
		if (rxL610RcvIdx != rxL610RdIdx)
		{
			printf("### rxL610RcvIdx = %d\r\n", rxL610RcvIdx);
			printf("### rxL610RdIdx = %d\r\n", rxL610RdIdx);
			printf("### Rx2BufIdx = %d\r\n", Rx2BufIdx);	
		}
	#endif
	}
#if debugDMADef
	if (rxL610RcvIdx != rxL610RdIdx)
	{
		printf("\r\n dma rcv data:\r\n");
		printf("### Rx2BufIdx = %d\r\n", Rx2BufIdx);
	}
#endif
	while(rxL610RcvIdx != rxL610RdIdx)
	{
		tagL610.rxDlyMaxSec = 0;	//清一条报文超过2秒自动清标志
	#if _EnSleep_def
		wakeup();
	#endif
		if (rxL610RdIdx != 0)
		{
			rxL610RdIdx --;
		}
		da = rxL610Buf[Rx2BufIdx];
	#if debugDMADef
		printf("%02x", da);
	#endif
		rxL610Buf[Rx2BufIdx] = 0x00;	//用过清0，防止程序错误导致反复解析
		Rx2BufIdx++;
		if ( Rx2BufIdx >= MAX_RECV_L610_IRT_LEN )
		{
			Rx2BufIdx = 0;
		}
		if (rxL610RdIdx == 0x00)
		{
			rxL610RdIdx = MAX_RECV_L610_IRT_LEN;
		#if debugDMADef
			printf("\r\n### rxL610RdIdx =  MAX_RECV_L610_IRT_LEN\r\n");
			printf("### Rx2BufIdx = %d\r\n", Rx2BufIdx);
		#endif
		}
		//当缓存都取光后，理论上应该下标就是.预防措施
		if (rxL610RcvIdx == rxL610RdIdx)
		{
			Rx2BufIdx = MAX_RECV_L610_IRT_LEN - rxL610RcvIdx;
		#if debugDMADef
			printf("\r\n### rxL610RcvIdx =  rxL610RdIdx = %d\r\n", rxL610RdIdx);
			printf("### Rx2BufIdx = %d\r\n", Rx2BufIdx);
		#endif
		}
		//正式的数据解析
		reDa = recv_L610_data(&da, 1);
	#if debugDMADef
		if (reDa == 1)
		{
			printf("\r\n### recv_L610_data reDa = %d\r\n", reDa);
			
			if (rxL610RcvIdx != rxL610RdIdx)
			{
				printf("### rxL610RcvIdx = %d\r\n", rxL610RcvIdx);
				printf("### rxL610RdIdx = %d\r\n", rxL610RdIdx);
				printf("### Rx2BufIdx = %d\r\n", Rx2BufIdx);
			}
		}
	#endif
		if ((reDa == 1) && (getOnlyL610GeneralAnswer() != 1))		//如果不是收到L610或PC的通用应答，则break后执行主程序
		{
			break;
		}
		else
		{
			clearOnlyL610GeneralAnswer();
		}
	#if debugDMADef
		if (rxL610RcvIdx == rxL610RdIdx)
		{
		printf("dma rcv end:\r\n");
		}
	#endif
	}
	//对PC串口的DMA解析部分
	//预防措施
	{
		clear_dma0_ch4_err();
	}
	//这样写，防止丢失数据
	if (rxPCRcvIdx == rxPCRdIdx)
	{
		//取出DMA剩余字节数
		//if( tagL610.uartPctime < 1800 )
		{
			rxPCRcvIdx = dma_transfer_number_get(DMA0, DMA_CH4);
		}
	#if debugPC_DMADef
		if (rxPCRcvIdx != rxPCRdIdx)
		{
			printf("### rxPCRcvIdx = %d\r\n", rxPCRcvIdx);
			printf("### rxPCRdIdx = %d\r\n", rxPCRdIdx);
		}
	#endif
	}
#if debugPC_DMADef
	if (rxPCRcvIdx != rxPCRdIdx)
	{
		printf("\r\n dma rcv PC data:\r\n");
	}
#endif
	while(rxPCRcvIdx != rxPCRdIdx)
	{
		tagL610.rxDlyMaxSec2 = 0;	//清一条报文超过2秒自动清标志
	#if _EnSleep_def
		wakeup();
	#endif
		if (rxPCRdIdx != 0)
		{
			rxPCRdIdx --;
		}
		da = rxPCBuf[RxPCBufIdx];	
	#if debugPC_DMADef
		printf("%02x", da);
	#endif
		rxPCBuf[RxPCBufIdx] = 0x00;	//用过清0，防止程序错误导致反复解析
		RxPCBufIdx++;
		if ( RxPCBufIdx >= MAX_RECV_L610_IRT_LEN )
		{
			RxPCBufIdx = 0;
		}
		
		if (rxPCRdIdx == 0x00)
		{
			rxPCRdIdx = MAX_RECV_L610_IRT_LEN;
		#if debugPC_DMADef
			printf("\r\n### rxPCRdIdx =  MAX_RECV_L610_IRT_LEN\r\n");
		#endif
		}
		//当缓存都取光后，理论上应该下标就是.预防措施
		if (rxPCRcvIdx == rxPCRdIdx)
		{
			RxPCBufIdx = MAX_RECV_L610_IRT_LEN - rxPCRcvIdx;
			#if debugPC_DMADef
			printf("\r\n### rxPCRcvIdx =  rxPCRdIdx = %d\r\n", rxPCRdIdx);
			#endif
		}
		//正式的数据解析
		reDa = recv_PC_data(&da, 1);
		etc_recv_msg_cache(&da, 1);
	#if debugPC_DMADef
		if (reDa == 1)
		{
			printf("\r\n### recv_PC_data reDa = %d\r\n", reDa);
		}
	#endif
		if ((reDa == 1) && (getOnlyL610GeneralAnswer() != 1))		//如果不是收到L610或PC的通用应答，则break后执行主程序
		{
			//当收到一组完整的AT报文时，就让主程序的部分处理一次
			//不用担心，中断处理会继续收数，不会丢的
			break;
		}
		else
		{
			clearOnlyL610GeneralAnswer();
		}
	#if debugPC_DMADef
		if (rxPCRcvIdx == rxPCRdIdx)
		{
			printf("dma rcv PC end:\r\n");
		}
	#endif
	}
	/*处理ETC接收数据信息解析*/
	etc_recv_msg_protocol_handle();
	//发过来的一条完整报文，不能超过3秒
	if (( tagL610.deal_sta2 != 0) &&
			(tagL610.rxDlyMaxSec2 > 2))
	{
		tagL610.rxDlyMaxSec2 = 0;
		tagL610.deal_sta2 = 0;
	}
	//发过来的一条完整报文，不能超过3秒
	if (( tagL610.deal_sta != 0) &&
			(tagL610.rxDlyMaxSec > 2))
	{
		tagL610.rxDlyMaxSec = 0;
		tagL610.deal_sta = 0;
	}
	//ETC数据接收处理，不能超过3秒钟
	if (( etc_recv_msg.state != 0) &&
			(tagL610.rxDlyMaxSec2 > 2))
	{
		tagL610.rxDlyMaxSec2 = 0;
		etc_recv_msg.state = 0;
	}
	
	//定时给L610发心跳，超时重启L610
	HeartBeat2L610();
	//处理主动上报
	//if (tagL610.activePushMsgSta == 1)
	{
		MsNew = get1msCounter();
		/*
		解释一下，因为GD主发不等应答就会再次主发，造成L610串口缓存较多，有可能1次返回几十条报文应答
		这样会导致再接收升级数据时DMA缓存越界。 所以增加判断(rxL610RcvIdx == rxL610RdIdx)
		*/
		if ((getTim1MsElaps(MsNew, MsOld) > _MS(200)) && 	//超过时间
				(rxL610RcvIdx == rxL610RdIdx))		//并且所有缓存处理完毕
		{
			MsOld = MsNew;
			deal_active_push_msg();
		}
	}
	/*车辆数据发送处理功能*/
	vehicle_data_handle_function();
	//用于实时查询ECU信息上报，根据车身返回查询是否结束
	if (GetCheckAESta() == 0x02)
	{
		SetCheckAESta(0);
		PushDataFlowToL610();
	}
	if (GetCheckAFSta() == 0x02)
	{
		SetCheckAFSta(0);
		PushDTCSaveDataToL610();
	}
	if (GetCheckPIDSta() == 0x02)
	{
		SetCheckPIDSta(0);
		answerCarInf_PIDList(0x02);
	}
	if (GetCheckErrListSta() == 0x02)
	{
		
		SetCheckErrListSta(0);
		answerCarInf_errorList(0x03);
	}
	if (GetCheckMendSta() == 0x02)
	{
		SetCheckMendSta(0);
		answerCarInf_mend(0x04);
	}
	//判断继电器供电或断电，并执行
#if !def_EngineStart
#if 0	/*不能直接控制继电器，需要进行状态判断。2022.05.20 YXX*/
	judgeRelayPower();
#endif
	RelayCtrlManage();	/*继电器控制管理*/
#endif
}

//ETC数据缓存，将串口接收到的数据缓存起来进行数据判断
void etc_recv_msg_cache( uint8_t *buf, uint32_t len )
{
	uint32_t i= 0;

	for ( i = 0; i < len; i++ )
	{
		switch ( etc_recv_msg.state )
		{
		case 0:
			if( buf[i] == 0x55 )
			{
				etc_recv_msg.len = 0;
				etc_recv_msg.state++;
				etc_recv_msg.data[etc_recv_msg.len++] = buf[i];
			}
			break;
		case 1:
			if( buf[i] == 0x33 )
			{
				etc_recv_msg.state++;
				etc_recv_msg.data[etc_recv_msg.len++] = buf[i];
			}	
			break;
		case 2:
			etc_recv_msg.data[etc_recv_msg.len++] = buf[i];
			if( etc_recv_msg.len >= ETC_RECV_MSG_LEN )
			{
				etc_recv_msg.state = 0;
			}
			break;
		default:
			etc_recv_msg.state = 0;
			break;
		}
	}
}

//ETC数据解析，并通过串口进行发送
void etc_recv_msg_protocol_handle( void )
{
	uint32_t data_len = 0, postion = 0;
	uint8_t crc8 = 0;

	if( etc_recv_msg.len != 0 )
	{
		for( postion = 0; postion < etc_recv_msg.len; postion++ )
		{
			if(( etc_recv_msg.data[postion] == 0x55 ) && ( etc_recv_msg.data[postion+1] == 0x33 ))
			{
				data_len = etc_recv_msg.data[postion + 2];
				break;
			}
		}
		if(( data_len != 0 ) && ( ( etc_recv_msg.len - postion ) >= ( data_len + 3 + 1 ) ) )
		{
			crc8 = etc_recv_msg_crc8((uint8_t *)&etc_recv_msg.data[postion+1], data_len + 2 );
			if( crc8 == etc_recv_msg.data[postion + data_len + 3] )
			{
				send_general_package_to_uart(0x2082, ( uint8_t *)&etc_recv_msg.data[postion], ( data_len + 3 + 1 ), 0,0,1);
				memset((uint8_t *)&etc_recv_msg, 0x00, sizeof( etc_recv_msg_t ) );
			}
		}
	}
}

//ETC数据CRC校验
uint8_t etc_recv_msg_crc8( uint8_t *buffer, uint32_t bufSize )
{
	uint8_t crc = 0, i = 0;

	if ( bufSize <= 0 )
    {
        return crc;
    }
    while( bufSize-- != 0 )
    {
        for ( i = 0x80; i != 0; i /= 2 )
        {
            if ( (crc & 0x80) != 0)
            {
                crc *= 2;
                crc ^= 0x07; 
            }
            else
            {
                crc *= 2;
            }
            if ( (*buffer & i) != 0 )
            {
                crc ^= 0x07;
            }
        }  
        buffer++;
    }

    return crc;
}


//给L610发心跳，如果收不到心跳或其它报文则重启L610
void HeartBeat2L610(void)
{
	if (tagL610.heatBeatDlySec > 600)
	{
		tagL610.heatBeatDlySec = 0;
		sendHeartBeat2L610();
	}
}

//定时发心跳
uint32_t sendHeartBeat2L610(void)
{

	uint8_t sdata[8];
	
	memset(sdata, 0, 8);
	return send_general_package_to_uart(0x2005, sdata, 8, 0, 0, 1);
}

/*判断接收7E对
解析中断，
返回1代表收到了完整一组报文，
返回0未收全报文
*/
uint32_t recv_PC_data(uint8_t* pdata, uint32_t len)
{
	uint32_t i;
	for (i = 0; i < len;i++)
	{
		switch (tagL610.deal_sta2)
		{
		case 0:
			if (pdata[i] == 0x7E)
			{
				tagL610.deal_sta2++;
				tagL610.deal_index2 = 0;
			}
			break;

		case 1:
			if (pdata[i] != 0x7E)
			{
				tagL610.deal_sta2++;
				tagL610.deal_buf2[tagL610.deal_index2++] = pdata[i];
			}
			break;

		case 2:
			tagL610.deal_buf2[tagL610.deal_index2++] = pdata[i];
			if (pdata[i] == 0x7E)
			{
				tagL610.deal_index2--;	//去掉结尾的7e,只解析有效数据部分
				//调用一次格式解析
				formart_L610_uart_recv(tagL610.deal_buf2, tagL610.deal_index2);
				tagL610.deal_sta2 = 0;
				return 1;
			}
			if (tagL610.deal_index2 >= MAX_RECV_L610_LEN-1)
			{
				tagL610.deal_sta2 = 0;
			}
			break;

		default:
			tagL610.deal_sta2 = 0;
			break;
		}
	}
	
	return 0;
	
}

/*判断接收7E对
解析中断，
返回1代表收到了完整一组报文，
返回0未收全报文
*/
uint32_t recv_L610_data(uint8_t* pdata, uint32_t len)
{
	uint32_t i;
		
	if (len >= MAX_RECV_L610_LEN)
	{
		return 0;
	}

	for (i = 0; i < len;i++)
	{
		switch (tagL610.deal_sta)
		{
		case 0:
			if (pdata[i] == 0x7E)
			{
				tagL610.deal_sta++;
				tagL610.deal_index = 0;
			}
			break;

		case 1:
			if (pdata[i] != 0x7E)
			{
				tagL610.deal_sta++;
				tagL610.deal_buf[tagL610.deal_index++] = pdata[i];
			}
			break;

		case 2:
			tagL610.deal_buf[tagL610.deal_index++] = pdata[i];
			if (pdata[i] == 0x7E)
			{
				tagL610.deal_index--;	//去掉结尾的7e,只解析有效数据部分
				//调用一次格式解析
				formart_L610_uart_recv(tagL610.deal_buf, tagL610.deal_index);
				tagL610.deal_sta = 0;
				return 1;
			}
			if (tagL610.deal_index >= MAX_RECV_L610_LEN-1)
			{
				tagL610.deal_sta = 0;
			}
			break;

		default:
			tagL610.deal_sta = 0;
			break;
		}
	}
	
	return 0;
}

/*7E转义
*/
void formart_L610_uart_recv(uint8_t* pdata, uint32_t len)
{
	uint32_t i, j;

	for (i = 0, j = 0; i < len; i++)
	{
		if ((pdata[i] == 0x7D) && (pdata[i + 1] == 0x02) && ((i + 1)<len))
		{
			pdata[j++] = 0x7E;
			i++;
		}
		else if ((pdata[i] == 0x7D) && (pdata[i + 1] == 0x01) && ((i + 1)<len))
		{
			pdata[j++] = 0x7D;
			i++;
		}
		else
		{
			pdata[j++] = pdata[i];
		}
	}

	len = j;
	
#if _EN_L610Debug_def	//调试信息
	printf("\r\nrcv from L610 Or PC 转义后\r\n");
	printf("%02x ", 0x7e);
	for (i = 0; i < len; i++)
	{
		printf("%02x ", pdata[i]);
	}
	printf("%02x ", 0x7e);
	printf("\r\n");
#endif
	
	//判断校验
	if (get_chk_xor(pdata, len) != 0x00)
	{
		#if _EN_L610Debug_def	//调试信息
		printf("check xor error\r\n");
		#endif
		return;
	}
	
	parse_L610_uart_data(pdata, len);
}



//增加7e格式发给单片机
//sel = 0, 发给串口0，发给L610；
//sel = 2，发给串口2，发给PC
uint32_t format_and_send_to_uart(uint8_t * pdata, uint32_t len, uint8_t sel)
{
#define MAX_LEN		(MAX_SEND_L610_LEN - 1)
	
	uint8_t fdata[MAX_LEN+1];
	uint8_t * p_data;	//原始数据指针
	uint8_t * tx_buf;	//格式化后的数据指针
	uint32_t j;
	uint32_t len_data;
	uint32_t txlen;


	if (len > MAX_LEN)
	{
		return 1;
	}

	p_data = pdata;
	len_data = len;
	tx_buf = fdata;
	txlen = 0;

	tx_buf[txlen++] = 0x7e;;

	//消息转译
	for (j = 0; j < len_data; j++)
	{
		if (*p_data == 0x7E)
		{
			tx_buf[txlen++] = 0x7D;
			tx_buf[txlen++] = 0x02;
		}
		else if (*p_data == 0x7D)
		{
			tx_buf[txlen++] = 0x7D;
			tx_buf[txlen++] = 0x01;
		}
		else
		{
			tx_buf[txlen++] = *p_data;
		}

		p_data++;

		if (txlen >= MAX_LEN)
		{
			return 2;
		}
	}

	tx_buf[txlen++] = 0x7E;

	if (sel == 0x00)
	{
		uart_send_to_PC(tx_buf, txlen);
	}
	else
	{
		uart_send_to_L610(tx_buf, txlen);
	}
	
	
	return 0;
}



//增加7e格式发给单片机
//返回0成功，其他值失败
uint32_t format_and_send_to_PC(uint8_t * pdata, uint32_t len)
{
	return format_and_send_to_uart(pdata, len, 0);
}

//增加7e格式发给单片机
uint32_t format_and_send_to_mcu(uint8_t * pdata, uint32_t len)
{
	return format_and_send_to_uart(pdata, len, 1);
}



//成功返回0，失败返回1
uint32_t uart_send_to_PC(uint8_t* pdata, uint32_t len)
{
	uint32_t ret;

	#if _EN_L610Debug_def
	{
		uint32_t i;
		printf("\r\ntx to PC:\r\n");
		for (i = 0; i < len;i++)
		{
			printf("%02x ", pdata[i]);
		}
		printf("\r\n");
	}
#endif
	
	ret = writeUart0(pdata, len);
	
	return ret;
	
}

//成功返回0，失败返回1
uint32_t uart_send_to_L610(uint8_t* pdata, uint32_t len)
{
	uint32_t ret;
	
	
#if _EN_L610Debug_def
	{
		uint32_t i;
		printf("\r\ntx to L610:\r\n");
		for (i = 0; i < len;i++)
		{
			printf("%02x ", pdata[i]);
		}
		printf("\r\n");
	}
#endif
	
	ret = writeUart1(pdata, len);
	
	return ret;
	
}




/*
写入车辆编号
以后可以使用设备注册号
*/
uint32_t get_para_car_id(uint8_t * ret_id)
{
	memcpy(ret_id, "123456", 6);
	return 0;
}

/*
写入流水号到2个字节
*/
uint32_t fill_serial_num(uint8_t * num)
{
	static uint16_t serial_num = 0;
	
	serial_num++;
	if (serial_num > 0xFFF0)
	{
		serial_num = 1;
	}

	num[0] = (serial_num / 0x100) % 0x100;
	num[1] = serial_num % 0x100;
	//返回2字节流水号
	return 0;
}



//返回utc时间给L610
uint32_t send_utc_to_L610(void)
{
	uint8_t sdata[5];
	u32toHex4(getCurrnetUtc(), sdata);
	return send_general_package_to_uart(0x2019, sdata, 4, 0,0,1);
	
}



uint32_t send2L610Alert(uint8_t type, uint32_t content)
{
	uint8_t sdata[6];
	
	sdata[0] = type;
	u32toHex4(content, sdata+1);
	
	return send_general_package_to_uart(0x2022, sdata, 5, 0,0,1);
	
}


//发通用答应
uint32_t send_general_answer_to_PC(uint32_t cmd, uint32_t serial_num, uint8_t sta)
{
	uint16_t idx;
	uint8_t sdata[100];
	uint32_t txlen;

	//Message_ID
	idx = 0;
	memcpy(&sdata[idx], "\x20\x00", 2);
	idx += 2;

	//Message_Property,afterward
	idx += 2;

	//Terminal_Num
	get_para_car_id(&sdata[idx]);
	idx += 6;

	//Message_Serial_Number
	fill_serial_num(&sdata[idx]);
	idx += 2;

	//content
	//应答流水号
	sdata[idx++] = (uint8_t)(serial_num >> 8);
	sdata[idx++] = (uint8_t)(serial_num);

	//应答ID
	sdata[idx++] = (uint8_t)(cmd >> 8);
	sdata[idx++] = (uint8_t)(cmd);

	//结果
	sdata[idx++] = sta;

	//消息体属性
	txlen = idx + 1;
	if (txlen < 13)
	{
		txlen = 13;
	}
	sdata[2] = (uint8_t)((txlen - 13) >> 8);
	sdata[3] = (uint8_t)(txlen - 13);

	//校验
	sdata[idx] = get_chk_xor(sdata, idx);
	idx++;

	format_and_send_to_PC(sdata, idx);
	
	return 0;
}

//发通用答应
uint32_t send_general_answer_to_L610(uint32_t cmd, uint32_t serial_num, uint8_t sta)
{
	uint16_t idx;
	uint8_t sdata[100];
	uint32_t txlen;

	//Message_ID
	idx = 0;
	memcpy(&sdata[idx], "\x20\x00", 2);
	idx += 2;

	//Message_Property,afterward
	idx += 2;

	//Terminal_Num
	get_para_car_id(&sdata[idx]);
	idx += 6;

	//Message_Serial_Number
	fill_serial_num(&sdata[idx]);
	idx += 2;

	//content
	//应答流水号
	sdata[idx++] = (uint8_t)(serial_num >> 8);
	sdata[idx++] = (uint8_t)(serial_num);

	//应答ID
	sdata[idx++] = (uint8_t)(cmd >> 8);
	sdata[idx++] = (uint8_t)(cmd);

	//结果
	sdata[idx++] = sta;

	//消息体属性
	txlen = idx + 1;
	if (txlen < 13)
	{
		txlen = 13;
	}
	sdata[2] = (uint8_t)((txlen - 13) >> 8);
	sdata[3] = (uint8_t)(txlen - 13);

	//校验
	sdata[idx] = get_chk_xor(sdata, idx);
	idx++;

	format_and_send_to_mcu(sdata, idx);
	
	return 0;
}

uint32_t sendGDVersion2L610(void)
{
	return send_general_package_to_uart(0x2013, (uint8_t*)_def_verson, 9, 0, 0, 1);
}

//秒增加,每秒加1
void L610SecInc(void)
{
	
	//凌晨2~4点重启L610
	RebootL610CntPlus();
	
	//后台要求重启CAN
	if (tagL610.restartCANHardware == 0x01)
	{
		tagL610.restartCANHardware = 0x02;
		turnOffCANs();
	}
	else if (tagL610.restartCANHardware == 0x02)
	{
		tagL610.restartCANHardware = 3;
	}
	else if (tagL610.restartCANHardware == 0x03)
	{
		tagL610.restartCANHardware = 0;
		InitCANConfig();
	}

	//收串口数据完整性判断延时
	if (tagL610.rxDlyMaxSec < 0xF0)
	{
		tagL610.rxDlyMaxSec++;
	}
	

	if (tagL610.rxDlyMaxSec2 < 0xF0)
	{
		tagL610.rxDlyMaxSec2++;
	}
	
	
	//给L610发心跳间隔
	if (tagL610.heatBeatDlySec < 0xFFF0)
	{
		tagL610.heatBeatDlySec++;
	}
	
	//重启L610延时
	if (tagL610.rebootL610DlySec < 0xFFF0)
	{
		tagL610.rebootL610DlySec++;
		
		//目前按收不到L610数据，10分钟重启
		if (tagL610.rebootL610DlySec > 1200)
		{
			tagL610.rebootL610DlySec = 0;
			rebootL610();
		}
	}

	if (tagL610.rebootStep != 0)
	{
		tagL610.rebootStep ++;
		
		//进入重启L610步骤
		switch(tagL610.rebootStep)
		{
			case 0x01:
			case 0x02:
				//L610断电
				L610PowerOff();
				break;

			case 0x03:
			case 0x04:
				//等着电容上的电荷被用掉,内核是1.8V或1.2V
				break;

			case 0x05:
				//L610上电
				L610PowerOn();
				//重新启动MCU系统，后期增加由于复位L610系统后未来稳定性再次重启MCU系统。2022.04.25 YXX
				reBootMe(); 
				break;
			
			default:
				tagL610.rebootStep = 0;
				break;
		}
	}
	/*系统上电后，30min内允许PC接口通信，超出时间后禁止数据读取，防止系统不休眠*/
	if( tagL610.uartPctime < 1800 )
	{
		tagL610.uartPctime++;
	}
}

//延时2秒发送MCU版本号
void sendMcuVersionToL610(void)
{
	if (tagL610.sendMcuVersion == 0x01)
	{
		tagL610.sendMcuVersion = 0x02;
	}
	else if (tagL610.sendMcuVersion == 0x02)
	{
		sendGDVersion2L610();
		tagL610.sendMcuVersion = 0;
	}
}

//清重启计数
void clearRebootL610Sec(void)
{
	tagL610.rebootL610DlySec = 0;
}

void rebootL610(void)	
{
	tagL610.rebootStep = 1;
}

void rebootCANHardware(void)	
{
	tagL610.restartCANHardware = 1;
}

uint8_t rebootCANHardwareGet( void )
{
	return tagL610.restartCANHardware;
}

void sendMcuVersion(void)
{
	tagL610.sendMcuVersion = 1;
}

/*
给L610数据的通用版本
serialUse = 1使用上面下发的流水号；=0使用内部流水号
最大发送长度1024字节

发送成功返回0，遇到错误返回其他值

sel = 0,发给串口0 ，L610
sel= 2 发给串口2，PC
*/
uint32_t send_general_package_to_uart(uint32_t cmd, uint8_t * pDa, uint32_t len, uint32_t serial_num, uint8_t serialUse, uint8_t sel)
{
	uint16_t idx;
	uint8_t sdata[MAX_SEND_L610_LEN+1];
	uint32_t txlen;

	//Message_ID
	idx = 0;
	sdata[idx++] = (uint8_t)(cmd >> 8);
	sdata[idx++] = (uint8_t)(cmd);
	

	//Message_Property,afterward
	idx += 2;

	//Terminal_Num
	get_para_car_id(&sdata[idx]);
	idx += 6;

	//Message_Serial_Number
	if (serialUse == 1)
	{
		sdata[idx++] = (uint8_t)(serial_num >> 8);
		sdata[idx++] = (uint8_t)(serial_num);
	}
	else
	{
		fill_serial_num(&sdata[idx]);
		idx += 2;
	}

	//content
	if (len < MAX_SEND_L610_LEN)
	{
		memcpy(&sdata[idx], pDa, len);
		idx += len;
	}
	else
	{
		return 1;
	}
	

	//消息体属性
	txlen = idx + 1;
	if (txlen < 13)
	{
		txlen = 13;
	}
	sdata[2] = (uint8_t)((txlen - 13) >> 8);
	sdata[3] = (uint8_t)(txlen - 13);
	
	//新增，如果超过1023，则启用bit15 = 1，代表增加1024字节长度
	if ((sdata[2] & 0x04) == 0x04)
	{
		sdata[2] &= ~0x04;	//清bit10，置bit15=1
		sdata[2] |= 0x80;
	}

	//校验
	sdata[idx] = get_chk_xor(sdata, idx);
	idx++;

	if (sel == 0x01)
	{
		format_and_send_to_mcu(sdata, idx);
	}
	else 
	{
		format_and_send_to_PC(sdata, idx);
	}
	
	
	return 0;
}

//成功返回0，失败返回1，格式错误返回2，其它3
//成功返回0，失败返回1，格式错误返回2，其它3	
uint32_t uartWriteFlash(uint32_t adr, uint32_t len, uint8_t * pDa)
{
	Flash_Write_Data(adr, pDa, (uint16_t)len);
	return 0;
}

//成功返回0，失败返回1，格式错误返回2，其它3
uint32_t uartReadFlash(uint32_t adr, uint32_t len)
{
	uint8_t rdDa[MAX_RECV_L610_LEN];
	
	if (len > MAX_RECV_L610_LEN-1)
	{
		return 1;
	}
	
	Flash_Read_Data(adr, rdDa, len);
	
	return send_general_package_to_uart(0x201D, rdDa, len, 0,0,0);
}

//成功返回0，失败返回1，格式错误返回2，其它3
uint32_t uartEraseFlash(uint32_t adr, uint32_t len)
{
	uint32_t i;
	for(i=0;i<len;i++)
	{
		Flash_Erase(Sector_Erase,adr + i*4096);
	}
	
	return 0;
}

//返回1，代表收到的L610通用应答，主程序可以不用再循环一圈
uint8_t getOnlyL610GeneralAnswer(void)
{
	return tagL610.OnlyL610GeneralAnswer;
}

void clearOnlyL610GeneralAnswer(void)
{
	tagL610.OnlyL610GeneralAnswer = 0;
}

/*
存储供断电
1通电,2断电
返回0成功，1失败
*/
u8 saveRelay2Flash(u8 relayCtrl)
{
	uint8_t reDa;
 	uint8_t reDa2;
 	uint8_t wrbuf[8] = { 0 };

	if( relayCtrl == 0x01 )	/*控制继电器状态为上电状态*/
	{
		tagL610.relayPowerCtrl = relayCtrl;	
		tagL610.relayPowerSt = relayCtrl;
		/*填充FLASH保存的数据*******************/
		wrbuf[0] = 0xA2;
		wrbuf[1] = tagL610.relayPowerCtrl;
		wrbuf[2] = ~tagL610.relayPowerCtrl;
		wrbuf[3] = tagL610.relayPowerSt & 0x7F;	/*上电状态，最高位置0*/
	}
	else
	{
		tagL610.relayPowerCtrl = relayCtrl;
		/*填充FLASH保存的数据*******************/
		wrbuf[0] = 0xA2;
		wrbuf[1] = tagL610.relayPowerSt;
		wrbuf[2] = ~tagL610.relayPowerSt;
		wrbuf[3] = tagL610.relayPowerSt | 0x80;	/*断电状态，最高位置1*/
	}

	erase_fmc_flash(FMC_RELAY_STA_ADR, 1);
	reDa = write_fmc_flash(FMC_RELAY_STA_ADR, wrbuf, 4);
	reDa2 = write_fmc_flash(FMC_RELAY_STA_ADR+512, wrbuf, 4);
	//直接赋值给全局变量, 并直接硬件执行
#if 0	/*平台下发指令时，不能直接控制继电器需要对状态进行判断。2022.05.20 YXX*/
	#if !def_EngineStart
	judgeRelayPower(); 
	#endif
#endif
	if ( (reDa == 0) || (reDa2 == 0) )
	{
		return 0;
	}

 	return 1;
}

/*
存储供断电
1通电,2断电
返回0成功，1失败
*/
u8 saveRelayPowerFlash( u8 relayCtrl )
{
	uint8_t reDa;
 	uint8_t reDa2;
 	uint8_t wrbuf[8] = { 0 };
	
 	wrbuf[0] = 0xA2;
 	wrbuf[1] = tagL610.relayPowerCtrl;
 	wrbuf[2] = ~tagL610.relayPowerCtrl;
	if( tagL610.relayPowerCtrl == 0x01 )
	{
		wrbuf[3] = relayCtrl | 0x00;
	}
	else
	{
		wrbuf[3] = relayCtrl | 0x80;
	}

	erase_fmc_flash(FMC_RELAY_STA_ADR, 1);
	reDa = write_fmc_flash(FMC_RELAY_STA_ADR, wrbuf, 4);
	reDa2 = write_fmc_flash(FMC_RELAY_STA_ADR+512, wrbuf, 4);
	//直接赋值给全局变量, 并直接硬件执行
#if 0	/*平台下发指令时，不能直接控制继电器需要对状态进行判断。2022.05.20 YXX*/
	#if !def_EngineStart
	judgeRelayPower(); 
	#endif
#endif
	if ( (reDa == 0) || (reDa2 == 0) )
	{
		return 0;
	}

 	return 1;
}

/*
存储供断电
1通电,2断电
*/
u8 readRelay2Flash(void)
{
	uint8_t relayCtrlSta = 1,relayCtrlPowerSt = 1;
	uint8_t rdbuf[8] = { 0 };
	uint32_t reDa;
	
	reDa = read_fmc_flash(FMC_RELAY_STA_ADR, rdbuf, 4);
	if( (reDa == 0) && (rdbuf[0] == 0xA2) && (rdbuf[1] == (u8)(~rdbuf[2])) )
	{
		if(( rdbuf[1] == 0x01 ) || ( rdbuf[1] == 0x02 ))
		{
			relayCtrlSta = rdbuf[1];
		}
		if(( ( rdbuf[3] & 0x7F ) == 0x01 ) || ( ( rdbuf[3] & 0x7F ) == 0x02 ))
		{
			relayCtrlPowerSt = ( rdbuf[3] & 0x7F );
		}
		/*判断继电器保存的状态，当继电器为断电状态是对继电器标志位置断电标志*/
		if( rdbuf[3] != 0xFF )	/*为了兼容以前版本，第四个字节存储固定数据0xFF*/
		{
			if( ( rdbuf[3] & 0x80 ) == 0x80 )
			{
				if( relayCtrlSta != 0x02 )
				{
					relayCtrlSta = 0x02;
				}
			}
		}
	}
	else
	{
		//判断备份部分
		reDa = read_fmc_flash(FMC_RELAY_STA_ADR+512, rdbuf, 4);
		if ( (reDa == 0) && (rdbuf[0] == 0xA2) && (rdbuf[1] == (u8)(~rdbuf[2])) )
		{
			if(( rdbuf[1] == 0x01 ) || ( rdbuf[1] == 0x02 ))
			{
				relayCtrlSta = rdbuf[1];
			}
			if(( ( rdbuf[3] & 0x7F )  == 0x01 ) || ( ( rdbuf[3] & 0x7F ) == 0x02 ))
			{
				relayCtrlPowerSt =( rdbuf[3] & 0x7F );
			}
			/*判断继电器保存的状态，当继电器为断电状态是对继电器标志位置断电标志*/
			if( rdbuf[3] != 0xFF )/*为了兼容以前版本，第四个字节存储固定数据0xFF*/
			{
				if( ( rdbuf[3] & 0x80 ) == 0x80 )
				{
					if( relayCtrlSta != 0x02 )
					{
						relayCtrlSta = 0x02;
					}
				}
			}
		}
	}

	if (reDa != 0)
	{
		relayCtrlSta = 1;	//如果Flash损坏，则给设备上电
		relayCtrlPowerSt = 1;
	}
	else
	{
		//如果提取到错误值，则给设备上电
		if ((relayCtrlSta == 0) || (relayCtrlSta > 2))
		{
			relayCtrlSta = 1;
		}
		if( ( relayCtrlPowerSt == 0) || (relayCtrlPowerSt > 2) )
		{
			relayCtrlPowerSt = 1;
		}
	}
	//直接赋值给全局变量, 并直接硬件执行
	tagL610.relayPowerCtrl = relayCtrlSta;
	tagL610.relayPowerSt = relayCtrlPowerSt;
#if !def_EngineStart
	judgeRelayPower( relayCtrlPowerSt );	/*系统上电，需要根据控制状态对继电器进行控制*/
#endif
	return relayCtrlSta;
}

//供其它位置读取当前设备 后台要求的供电或断电
//返回1供电，返回2断电
u8 getCurrentRelayCtrlSta(void)
{
	//如果提取到错误值，则给设备上电
	if ((tagL610.relayPowerCtrl == 0) || (tagL610.relayPowerCtrl > 2))
	{
		tagL610.relayPowerCtrl = 1;
	}
	
	return tagL610.relayPowerCtrl;
}

void judgeRelayPower( uint8_t ctrl )
{
#if 0
	if (tagL610.relayPowerCtrlOld != tagL610.relayPowerCtrl)
	{
		tagL610.relayPowerCtrlOld = tagL610.relayPowerCtrl;
		
		if (tagL610.relayPowerCtrlOld == 0x02)
		{
			relayPowerOff_hw();
			#if USER_HXCX_ARCFOX
			tagCarC.Power_Ctrl = 0x80; //下电
			#endif
			ret = 1;
		}
		else
		{
			#if USER_HXCX_ARCFOX
			tagCarC.Power_Ctrl = 0x81; //上电
			relayPowerOff_hw();
			#else
			relayPowerOn_hw();
			#endif
			ret = 1;
		}
	}
#else
	if( tagL610.relayPowerCtrlOld != ctrl )
	{
		tagL610.relayPowerCtrlOld = ctrl;

		if( tagL610.relayPowerCtrlOld == 0x02 )
		{
			relayPowerOff_hw();
			#if USER_HXCX_ARCFOX
			tagCarC.Power_Ctrl = 0x80; //下电
			#endif
		}
		else
		{
			#if USER_HXCX_ARCFOX
			tagCarC.Power_Ctrl = 0x81; //上电
			relayPowerOff_hw();
			#else
			relayPowerOn_hw();
			#endif
		}
	}
#endif

}

//继电器控制管理
void RelayCtrlManage( void )
{
	uint8_t relay_st = 0, door_st = 0, lock_st = 0, acc_st = 0;
	uint16_t speed = 0;
	static uint16_t delay_old_time = 0, delay_new_time = 0;
	static uint32_t delay_10min = 0, delay_30s = 0;
	/*检测门状态 bit0:左前 bit1：右前 bit2：左后 bit3：右后 bit4：后备箱 bit5：前机舱盖*/
	if(( u8AutoDoorSt() & 0x0F ) != 0x00 )
	{
		door_st = 0x01;
	}
	else
	{
		door_st = 0x00;
	}
	/*检测锁状态 bit0:中控锁 bit1:断电 bit2：PKE设防 bit3:左前门锁 bit4:右前门锁 bit5:左后门锁 bit6:右后门锁*/
	if( ( u8AutoLockSt() & 0x01 ) == 0x01 ) /*开锁*/
	{
		lock_st = 0x01;
	}
	else
	{
		lock_st = 0x00;
	}
	/*检测ACC状态 bit0:上电信号 bit1:发动机信号 bit2:钥匙信号 bit3：ACC bi4：ON*/
	if(( u8AutoIgSt() & 0x08 ) == 0x08 )	/*ACC ON*/
	{
		acc_st = 0x01;
	}
	else
	{
		acc_st = 0x00;
	}
#if 0
	/*获取充电状态*/
	if( ( u8ChargeSt() & 0x03 ) != 0 )
	{
		if( tagL610.relayPowerSt != 0x01 )
		{
			tagL610.relayPowerSt = 0x01;
			judgeRelayPower( tagL610.relayPowerSt );
		}
		return;
	}
#endif
	/*获取当前车辆速度*/
	speed = u16AutoSpeed();
	/*读取继电器控制状态，1通电,2断电*/
	relay_st = getCurrentRelayCtrlSta();
	if( relay_st == 1 )
	{
		/*判断车门、车锁、ACC状态是否为*/
		if(( door_st == 0x00 ) && ( lock_st == 0x00 ) && ( acc_st == 0x00 ))
		{
			/*延迟10分钟，没有任何操作。继电器处于断电*/
			if( sleepStatue == 0x03 )
			{
				delay_10min += 40;
				if( delay_10min >= 600000 ) /*大于 10分钟，10 * 60 * 1000*/
				{
					delay_10min = 0;
					/*控制继电器，断电*/
					if( tagL610.relayPowerSt != 0x02 )
					{
						tagL610.relayPowerSt = 0x02;
					}
				}
			}
			else
			{
				delay_new_time = get1msCounter();
				if(getTim1MsElaps(delay_new_time , delay_old_time ) > _MS(40))
				{
					delay_old_time = get1msCounter();
					delay_10min += 40;
					if( delay_10min >= 600000 ) /*大于 10分钟，10 * 60 * 1000*/
					{
						delay_10min = 0;
						/*控制继电器，断电*/
						if( tagL610.relayPowerSt != 0x02 )
						{
							tagL610.relayPowerSt = 0x02;
						}
					}
				}
			}
		}
		else
		{
			delay_10min = 0;
			delay_old_time = get1msCounter();
			tagL610.relayPowerSt = 0x01;
		}
		delay_30s = 0;
	}
	else
	{
		if(( acc_st == 0x00 ) && ( speed == 0 ))
		{
			/*车辆熄火且速度为0,30秒后进行断电*/
			if( sleepStatue == 0x03 )
			{
				delay_30s += 40;
				if( delay_30s >= 1000 )	/*大于 30 *1000*//*测试发现需要快速关闭继电器，将以前30S修改为1S*/
				{
					delay_30s = 0;
					/*控制继电器断电*/
					if( tagL610.relayPowerSt != 0x02 )
					{
						tagL610.relayPowerSt = 0x02;
						saveRelayPowerFlash( tagL610.relayPowerSt );
					}
				}
			}
			else
			{
				delay_new_time = get1msCounter();
				if( getTim1MsElaps(delay_new_time , delay_old_time ) > _MS(40) )
				{
					delay_old_time = get1msCounter();
					delay_30s += 40;
					if( delay_30s >= 1000 )	/*大于 30 *1000*//*测试发现需要快速关闭继电器，将以前30S修改为1S*/
					{
						delay_30s = 0;
						/*控制继电器断电*/
						if( tagL610.relayPowerSt != 0x02 )
						{
							tagL610.relayPowerSt = 0x02;
							saveRelayPowerFlash( tagL610.relayPowerSt );
						}
					}
				}
			}
		}
		else
		{
			delay_30s = 0;
			delay_old_time = get1msCounter();
		}
		delay_10min = 0;
	}
	/*判断继电器状态是否为上电状态，如果为上电状态，直接将控制状态设置为上电*/
	judgeRelayPower( tagL610.relayPowerSt );
}

//获取随机数
uint32_t getRandom_u32(void)
{
	static uint8_t runOnce = 0;
	
	if (runOnce == 0)
	{
		//使用uuid初始化random函数，之后取数
		uint32_t Unique_ID1 = *(uint32_t *)(0x1FFFF7AC);        //UNIQUE_ID[31: 0]
		uint32_t Unique_ID2 = *(uint32_t *)(0x1FFFF7B0);        //UNIQUE_ID[63:32]
		uint32_t Unique_ID3 = *(uint32_t *)(0x1FFFF7B4);        //UNIQUE_ID[95:63]
		uint32_t seed;
		
		seed = Unique_ID1 ^ Unique_ID2;
		seed += Unique_ID3;
		srand(seed);
		runOnce = 1;
	}

	return rand();
}

/*
定时2~4点重启L610
*/
void setRebootL610Time(uint8_t * rtcTime)
{
	//比如设置时间是1点，实际是1:00~1:59,为了保证2~4点，所以增加下面换算
	tagL610.RebootL610Cnt = (rtcTime[3]%24) * 3600 + getRandom_u32()%3600;
	
	tagL610.requestRTCFromL610 = 3600;	//相当于退出10秒要时间逻辑，进入1小时要1次时间
	
	#if _EnRebootL610Debug_def
	printf("rcv time %d-%d-%d %d:%d:%d\r\n", rtcTime[0], rtcTime[1], rtcTime[2], 
										rtcTime[3], rtcTime[4], rtcTime[5]);
	#endif
}

//每秒调用1次，
void RebootL610CntPlus(void)
{
	static uint8_t waitAccOffReboot = 0;
	
	tagL610.RebootL610Cnt ++;
	
	if (tagL610.RebootL610Cnt > 24*3600)
	{
		tagL610.RebootL610Cnt = 0;
	}
	
	if (tagL610.RebootL610Cnt == 3*3600)
	{
		waitAccOffReboot = 1;
		#if _EnRebootL610Debug_def
		printf("reboot time arived\r\n");
		#endif
	}
	
	if ((waitAccOffReboot == 1) &&
		((u8AutoIgSt() & 0x08) == 0x00))	//非acc 时重启
	{
		waitAccOffReboot = 0;
		
		//reboot L610
		//rebootL610();			//重启L610
		#if _EnRebootL610Debug_def
		printf("rebootL610 at 2~4\r\n");
		#endif
		//重启后，过5个小时，再要时间1次
		tagL610.requestRTCFromL610 = (48-5)*3600;
	}
	
	tagL610.requestRTCFromL610++;
	//请求时间，每1小时调用1次，如果刚开机，每10分钟调用1次，应答成功后每1小时调用1次
	if (tagL610.requestRTCFromL610 < 100)
	{
		if ((tagL610.requestRTCFromL610 % 10) == 0)
		{
			//request_rtc_from_L610();
		}
	}
	else if (tagL610.requestRTCFromL610 > 48*3600)
	{
		tagL610.requestRTCFromL610 = 3600;	//相当于退出10秒要时间逻辑，进入1小时要1次时间
		//request_rtc_from_L610();
	}
	
}

//请求下发时间
uint32_t request_rtc_from_L610(void)
{
	uint8_t numb[1];
	
	#if _EnRebootL610Debug_def
	printf("request_rtc_from_L610\r\n");
	#endif
	
	return send_general_package_to_uart(0x2039, numb, 0, 0,0,1);
	
}

/*
切卡状态保存
1外卡,2内卡
返回0成功，1失败
*/
uint8_t saveSwSIMtoFlash(uint8_t sta)
{
		uint8_t i;
		uint8_t wrbuf[8]={0};
		uint8_t rdbuf[8]={0};
		wrbuf[0] = 0xA2;
		wrbuf[1] = sta;
		wrbuf[2] = ~sta;
		wrbuf[3] = get_chk_xor(wrbuf,3);
		 

		
		for (i=0;i<3;i++)
		{
			erase_fmc_flash(FMC_SWSIM_STA_ADR, 1);
			write_fmc_flash(FMC_SWSIM_STA_ADR, wrbuf, 4);
			
			read_fmc_flash(FMC_SWSIM_STA_ADR, rdbuf, 4);
			
			if ((memcmp(wrbuf, rdbuf, 4) == 0))
			{
				return 0;
			}
		}
		
		return 1;
}
/*
读取切卡状态
sta 1外卡,2内卡
返回0成功，1失败
*/
uint8_t readSwSIMfromFlash(uint8_t *sta)
{
	uint8_t DaRd[8]={0};

	uint8_t i, chkXor;
	
	for (i=0;i<3;i++)
	{
		read_fmc_flash(FMC_SWSIM_STA_ADR, DaRd, 4);
		chkXor = get_chk_xor(DaRd, 3);
		if ((DaRd[3] == chkXor) &&
			 (DaRd[0] == 0xA2))
		{
			*sta = DaRd[1]; 
			return 0;
		}
	}
	*sta = 0;
	return 1;
}

